#include "protocol_api.h"
#include "protocol_board.h"
#include "protocol_encryption.h"
#include "xor.h"
// #include "des.h"

uint16_t ProtocolEncryption(void *pOriginalData)
{
  uint8_t *pDataBuffOffset = NULL;
  uint8_t KeyValue[ENCRYPTION_KEY_LENGTH] = {0};
  uint16_t EncryptedDataLength = 0, MessageSize = 0;
  ProtocolFormat_t *pProtocolFormat = (ProtocolFormat_t *)pOriginalData;

  if (pOriginalData != NULL)
  {
    ProtocolGetEncryptionKey(KeyValue);
    EncryptedDataLength = ((pProtocolFormat->Length[0] << 8) | pProtocolFormat->Length[1]) + PROTOCOL_CAPTCHA_BIT_LENGTH + PROTOCOL_VERSION_BIT_LENGTH + PROTOCOL_CMD_BIT_LENGTH;
    if ((EncryptedDataLength % 16) != 0)
    {
      EncryptedDataLength += (16 - (EncryptedDataLength % 16));
    }

    pDataBuffOffset = pProtocolFormat->Captcha;
    for (uint8_t i = 0; i < EncryptedDataLength / 16; i++)
    {
      ProtocolCalculateAesEcbEncrypt(KeyValue, pDataBuffOffset);
      pDataBuffOffset += 16;
    }

    ProtocolGetOuterLayerEncryptionKey(KeyValue);
    EncryptedDataLength += PROTOCOL_RANDOM_BIT_LENGTH + PROTOCOL_TIMESTAMP_BIT_LENGTH + PROTOCOL_INDEX_BIT_LENGTH;
    if ((EncryptedDataLength % 16) != 0)
    {
      EncryptedDataLength += (16 - (EncryptedDataLength % 16));
    }

    pDataBuffOffset = pProtocolFormat->Random;
    for (uint8_t i = 0; i < EncryptedDataLength / 16; i++)
    {
      ProtocolCalculateAesEcbEncrypt(KeyValue, pDataBuffOffset);
      pDataBuffOffset += 16;
    }

    MessageSize = (EncryptedDataLength - (PROTOCOL_FIXED_BIT_LENGTH - (PROTOCOL_SYNCWORD_BIT_LENGTH + PROTOCOL_DATA_SIZE_BIT_LENGTH)));
    pProtocolFormat->Length[0] = (uint8_t)((MessageSize & 0xFF00) >> 8);
    pProtocolFormat->Length[1] = (uint8_t)(MessageSize & 0x00FF);
  }

  return EncryptedDataLength;
}

void ProtocolDecryption(void *pOriginalData)
{
  if (pOriginalData != NULL)
  {
    uint16_t DecryptDataLength = 0;
    uint8_t *pDataBuffOffset = NULL;
    uint8_t KeyValue[ENCRYPTION_KEY_LENGTH] = {0};
    ProtocolFormat_t *pProtocolFormat = (ProtocolFormat_t *)pOriginalData;

    ProtocolGetOuterLayerEncryptionKey(KeyValue);
    DecryptDataLength = ((pProtocolFormat->Length[0] << 8) | pProtocolFormat->Length[1]) + (PROTOCOL_FIXED_BIT_LENGTH - (PROTOCOL_SYNCWORD_BIT_LENGTH + PROTOCOL_DATA_SIZE_BIT_LENGTH));
    if ((DecryptDataLength % 16) == 0)
    {
      pDataBuffOffset = pProtocolFormat->Random;
      for (uint8_t i = 0; i < DecryptDataLength / 16; i++)
      {
        ProtocolCalculateAesEcbDecrypt(KeyValue, pDataBuffOffset);
        pDataBuffOffset += 16;
      }

      ProtocolGetEncryptionKey(KeyValue);
      DecryptDataLength -= (PROTOCOL_RANDOM_BIT_LENGTH + PROTOCOL_TIMESTAMP_BIT_LENGTH + PROTOCOL_INDEX_BIT_LENGTH);
      if ((DecryptDataLength % 16) == 0)
      {
        pDataBuffOffset = pProtocolFormat->Captcha;
        for (uint8_t i = 0; i < DecryptDataLength / 16; i++)
        {
          ProtocolCalculateAesEcbDecrypt(KeyValue, pDataBuffOffset);
          pDataBuffOffset += 16;
        }
      }
    }
  }
}

/**
 * 计算数据块的异或校验值 (XOR Checksum)
 * 
 * 原理：将数据块中的所有字节依次进行异或(XOR)运算。
 *       异或运算特性：相同为0，不同为1；A ^ A = 0；A ^ 0 = A。
 *       因此，校验值可以用于检测单个比特的翻转（奇数个比特错误通常能被检测到）。
 * 
 * @param data      指向待校验数据的指针 (const void* 可以接受各种指针类型)
 * @param length    数据的长度（字节数）
 * @return          计算得到的8位异或校验值 (uint8_t)
 * 
 * @note            如果 length 为 0，函数返回 0。
 */
static uint8_t calculate_xor_checksum(const void* data, size_t length) {
    // 将通用指针转换为指向 uint8_t 的指针，便于按字节访问
    const uint8_t* byte_data = (const uint8_t*)data;
    uint8_t checksum = 0; // 初始化校验值为 0
    
    // 遍历数据块中的每一个字节
    for (size_t i = 0; i < length; i++) {
        checksum ^= byte_data[i]; // 将当前字节与校验值进行异或运算
    }
    
    return checksum; // 返回最终的校验值
}

// extern uint32_t GetGmtTimestamp(void);
extern uint32_t RealTimeMakeCurrentTimestamp(void);
ErrorCode_t BleBoardcastDataDecrypt(uint8_t *pBoardcastData, uint8_t BoardcastDataLen)
{

  if (pBoardcastData != NULL)
  {
    uint8_t *Ptr = &pBoardcastData[0];
    

    //1.校验头是否正确
    if (Ptr[0] != BOARDCAST_FIX_HEADER)
    {
      return ENCRYPTION_FIX_HEADER_ERROR;
    }

    if (BoardcastDataLen != BOARDCAST_FIX_DATA_LEN)
    {
      return ENCRYPTION_DATA_LEN_ERROR;
    }

    //2.校验异或是否正确

    uint8_t XorCalcValue = calculate_xor_checksum(Ptr, BoardcastDataLen-1);

    if (XorCalcValue != Ptr[BoardcastDataLen-1])
    {
      PRINT("[protocol]: XorCalcValue = %02x, Ptr[BoardcastDataLen-1] = %02x\r\n", XorCalcValue, Ptr[BoardcastDataLen-1]);

      return ENCRYPTION_XOR_ERROR;
    }

    //3.用密钥对黄色背景部分进行循环异或得到
    uint8_t SectorKeyValue[READCARD_MAX_NUMBER_OF_CODED_TEXT] = {0};
    ProtocolGetElevatorSectorAccessKey(SectorKeyValue); 
    //打印密钥
    // PRINT("[protocol]: SectorKeyValue\r\n");
    // for(uint8_t i = 0; i < 6; i++)
    // {
    //   PRINT("%02x", SectorKeyValue[i]);
    // }
    // PRINT("\r\n");
    //打印数据
    // PRINT("[protocol]: before BoardcastData\r\n");
    // for(uint8_t i = 0; i < BoardcastDataLen; i++)
    // {
    //   PRINT("%02x ", Ptr[i]);
    // }
    // PRINT("\r\n");
    XorDecryptCalculate(SectorKeyValue, 6, &Ptr[1], BoardcastDataLen-2);
    // PRINT("[protocol]: after BoardcastData 1\r\n");
    // for(uint8_t i = 0; i < BoardcastDataLen; i++)
    // {
    //   PRINT("%02x ", Ptr[i]);
    // }
    // PRINT("\r\n");

    //4.用随机数对下划线部分进行异或得到
    memset(&SectorKeyValue, 0, READCARD_MAX_NUMBER_OF_CODED_TEXT);
    SectorKeyValue[0] = Ptr[1];
    XorDecryptCalculate(SectorKeyValue, 1, &Ptr[2], BoardcastDataLen-3);
    // PRINT("[protocol]: after BoardcastData 2\r\n");
    // for(uint8_t i = 0; i < BoardcastDataLen; i++)
    // {
    //   PRINT("%02x ", Ptr[i]);
    // }
    // PRINT("\r\n");
    //验证时间
    uint8_t TimeStamp[4] = {0};
    TimeStamp[0] = Ptr[2];
    TimeStamp[1] = Ptr[3];
    TimeStamp[2] = Ptr[4];
    TimeStamp[3] = Ptr[5];
    if (GetStartTimeVerifyEn() == true)
    {
      uint32_t NowTimestamp = RealTimeMakeCurrentTimestamp();
      uint32_t BleBoardDataTimestamp = TimeStamp[0] << 24 | TimeStamp[1] << 16 | TimeStamp[2] << 8 | TimeStamp[3];
      if (abs((int)(BleBoardDataTimestamp - NowTimestamp)) <= 3600)//一个小时
      {
        //时间验证通过

      }else
      {
        PRINT("[centrla]: ENCRYPTION_TIME_ERROR BleBoardDataTimestamp = %u, NowTimestamp = %u\r\n", BleBoardDataTimestamp, NowTimestamp);

        return ENCRYPTION_TIME_ERROR;
      }
    }
    XorDecryptCalculate(TimeStamp, 4, &Ptr[6], 4);
    // PRINT("[protocol]: after BoardcastData 3\r\n");
    // for(uint8_t i = 0; i < BoardcastDataLen; i++)
    // {
    //   PRINT("%02x ", Ptr[i]);
    // }
    // PRINT("\r\n");

    //5.判断红字加粗部分是否为5947
    if (Ptr[6] != 0x59 || Ptr[7] != 0x47)
    {
      return ENCRYPTION_FIX_FLAG_ERROR;
    }

    return ENCRYPTION_OK;

  }

  return ENCRYPTION_ERROR;
}